#ifndef MATRIX_HPP
#define MATRIX_HPP
#include "GLHeaders.hpp"
#include <cmath>
#include "Vector.hpp"

// My own 3*3 Column-major matrix class

class Matrix{
public:
	Vector v0, v1, v2;

public:
	//Constructor
	Matrix(void);
	Matrix(
			const GLfloat fa00,//3×3 column-major matrix
			const GLfloat fa10,
			const GLfloat fa20,
			const GLfloat fa01,
			const GLfloat fa11,
			const GLfloat fa21,
			const GLfloat fa02,
			const GLfloat fa12,
			const GLfloat fa22);
	Matrix(
			const Vector& vector0,
			const Vector& vector1,
			const Vector& vector2);
  Matrix(const Matrix& matrix);
  
  //Arithmetic operations
  Matrix operator + () const;
  Matrix operator - () const;
  Matrix operator + (const Matrix& rhs) const;
  Matrix operator + (const GLfloat& value) const;
  Matrix operator - (const Matrix& rhs) const;
  Matrix operator - (const GLfloat& value) const;
  Matrix operator * (const Matrix& rhs) const;
  Vector operator * (const Vector& rhs) const;
  Matrix operator * (const GLfloat& value) const;
  Matrix operator / (const Matrix& rhs) const;
  Matrix operator / (const GLfloat& value) const;

  //Friend Methods
  friend Matrix operator + (const GLfloat& value, const Matrix& lhs);
  friend Matrix operator - (const GLfloat& value, const Matrix& lhs);
  friend Matrix operator * (const GLfloat& value, const Matrix& rhs);
  friend Matrix operator / (const GLfloat& value, const Matrix& rhs);

  //Boolean operation
  bool operator <  (const Matrix& rhs) const;
  bool operator <= (const Matrix& rhs) const;
  bool operator == (const Matrix& rhs) const;  
  bool operator != (const Matrix& rhs) const;
  bool operator >= (const Matrix& rhs) const;
  bool operator >  (const Matrix& rhs) const;
  
  //Arithmetic updates
  Matrix& operator =  (const Matrix& rhs);
  Matrix& operator =  (const GLfloat& value);
  Matrix& operator += (const Matrix& rhs);
  Matrix& operator += (const GLfloat& value);
  Matrix& operator -= (const Matrix& rhs);
  Matrix& operator -= (const GLfloat& value);
  Matrix& operator *= (const Matrix& rhs);
  Matrix& operator *= (const GLfloat& value);
  Matrix& operator /= (const Matrix& rhs);
  Matrix& operator /= (const GLfloat& value);

  //Functions
  GLfloat Determinant(void) const;//Determinant
  Matrix Inverse(void) const;// Inverse (Determinant != 0.0f!)
  Matrix Transpose(void) const;//Transpose
  void Copy3f(GLfloat* tab) const;//3×3 column-major matrix
  void Copy4f(GLfloat* tab) const;//4×4 column-major matrix
	void glRotate(void) const; // apply a rotation to MODEL_VIEW_MAT
	static Matrix Rotate(
			const GLfloat fangle,
			const GLfloat fx,
			const GLfloat fy,
			const GLfloat fz);


  //Special matrix
  static const Matrix ZERO;
  static const Matrix ONES;
  static const Matrix IDENTITY;
  static const Matrix RX_90; 
  static const Matrix RY_90; 
  static const Matrix RZ_90; 
  static const Matrix NEGATIVE_RX_90; 
  static const Matrix NEGATIVE_RY_90; 
  static const Matrix NEGATIVE_RZ_90; 
 };

#endif
